package com.kl.turn;

import lombok.extern.slf4j.Slf4j;

/**
 * 交替输出 wait/notify
 * 要求：三个线程交替打印出ABC，总共打印5次
 * 思路：
 * 三个线程交替打印，我们需要通过一个标志位来判断当前由哪个线程进行打印，boolean只能表示2种状态，我们可以选择int型
 * 每个线程携带一个自己的标记，与共享资源中的标记比对，相同就允许该线程操作资源类，否则就阻塞等待唤醒
 * 当标记位为1的时候线程1开始打印，打印结束后将标记位设置为2，通知线程2开始打印
 * 当标记位为2的时候线程2开始打印，打印结束后将标记位设置为3，通知线程3开始打印
 * 当标记位为3的时候线程3开始打印，打印结束后将标记位设置为1，通知线程1开始打印
 */
@Slf4j
public class AlternateTest {
    private int flag;
    private final int loopNum;

    AlternateTest(int flag, int loopNum) {
        this.flag = flag;
        this.loopNum = loopNum;
    }

    public void print(String num, int flag, int nextFlag) {
        for (int i = 0; i < loopNum; i++) {
            synchronized (this) {
                while (flag != this.flag) { //通过标志位判断是否允许当前进入的线程运行
                    try {
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.info(num);
                this.flag = nextFlag;
                this.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        //初始化标记位为1,表示允许线程1先运行,交替打印2次
        AlternateTest alternateTest = new AlternateTest(1, 10);
        new Thread(() -> {
            alternateTest.print("A", 1, 2);
        }, "线程1").start();
        new Thread(() -> {
            alternateTest.print("B", 2, 3);
        }, "线程2").start();
        new Thread(() -> {
            alternateTest.print("C", 3, 1);
        }, "线程3").start();
    }
}